import { Reducer } from 'redux';
import { StateType as SsqDataListStateType } from '@/models/SsqDataList';

export interface ListItemType {
  code: string,
  date: string,
  red1: number,
  red2: number,
  red3: number,
  red4: number,
  red5: number,
  red6: number,
  blue: number,
  level: number,
  levelDesc: string,
}

export interface SummaryType {
  totalCount: number;
  level1Count: number;
  level2Count: number;
  level3Count: number;
  level4Count: number;
  level5Count: number;
  level6Count: number;
}

export interface StateType {
  dataSource?: ListItemType[],
  summary?: SummaryType
}

interface ModelType {
  namespace: string;
  state: StateType;
  reducers: {
    predict: Reducer<StateType>;
  };
}

const getTop = (arr: number[], count: number): number[] | undefined => {
  const map: Map<number, number> = new Map<number, number>();
  for (let number of arr) {
    let count = map.get(number) || 0;
    map.set(number, count + 1);
  }
  if (map.size < count) {
    return undefined;
  }
  const countArr = Array.from(map);
  countArr.sort((a, b) => b[1] - a[1]);
  return countArr.map(item => item[0]).slice(0, count).sort((a, b) => a - b);
};

interface Level {
  level: number,
  levelDesc: string
}

const getLevel = (predictionData: ListItemType, data: SsqDataListStateType): Level => {
  let redCount = 0;
  let blueCount = 0;
  const dataReds = [data.red1, data.red2, data.red3, data.red4, data.red5, data.red6];
  if (dataReds.includes(predictionData.red1)) redCount++;
  if (dataReds.includes(predictionData.red2)) redCount++;
  if (dataReds.includes(predictionData.red3)) redCount++;
  if (dataReds.includes(predictionData.red4)) redCount++;
  if (dataReds.includes(predictionData.red5)) redCount++;
  if (dataReds.includes(predictionData.red6)) redCount++;
  if (data.blue === predictionData.blue) blueCount++;
  if (redCount === 6 && blueCount === 1) {
    return {
      level: 1,
      levelDesc: '一等奖',
    };
  }
  if (redCount === 6 && blueCount === 0) {
    return {
      level: 2,
      levelDesc: '二等奖',
    };
  }
  if (redCount === 5 && blueCount === 1) {
    return {
      level: 3,
      levelDesc: '三等奖',
    };
  }
  if ((redCount === 5 && blueCount === 0)
    || (redCount === 4 && blueCount === 1)) {
    return {
      level: 4,
      levelDesc: '四等奖',
    };
  }
  if ((redCount === 4 && blueCount === 0)
    || (redCount === 3 && blueCount === 1)) {
    return {
      level: 5,
      levelDesc: '五等奖',
    };
  }
  if (redCount < 3 && blueCount === 1) {
    return {
      level: 6,
      levelDesc: '六等奖',
    };
  }
  return {
    level: 0,
    levelDesc: '很遗憾',
  };
};

const Model: ModelType = {
  namespace: 'ssqPredictionData',
  state: {},
  reducers: {
    predict(state, { payload }) {
      const sampleCount = payload.sampleCount;
      const ssqDataList: SsqDataListStateType[] = [...payload.ssqDataList].reverse();
      const predictionDataList: ListItemType[] = [];
      let totalCount = 0;
      const levelCount = [0, 0, 0, 0, 0, 0, 0];
      for (let i = 0; i < ssqDataList.length; i++) {
        if (i < sampleCount) {
          continue;
        }
        const allReds = ssqDataList.slice(i - sampleCount, i)
          .reverse()
          .flatMap(item => [item.red1, item.red2, item.red3, item.red4, item.red5, item.red6]);
        const predictionReds = getTop(allReds, 6);
        const allBlues = ssqDataList.slice(i - sampleCount, i)
          .map(item => item.blue);
        const predictionBlue = getTop(allBlues, 1);
        const current = ssqDataList[i];
        if (predictionReds && predictionBlue) {
          const predictionData = {
            code: current.code,
            date: current.date,
            red1: predictionReds[0],
            red2: predictionReds[1],
            red3: predictionReds[2],
            red4: predictionReds[3],
            red5: predictionReds[4],
            red6: predictionReds[5],
            blue: predictionBlue[0],
            level: 0,
            levelDesc: '很遗憾',
          };
          const level = getLevel(predictionData, current);
          predictionData.level = level.level;
          predictionData.levelDesc = level.levelDesc;
          predictionDataList.push(predictionData);
          totalCount++;
          levelCount[level.level]++;
        }
      }
      predictionDataList.reverse();
      return {
        dataSource: predictionDataList,
        summary: {
          totalCount,
          level1Count: levelCount[1],
          level2Count: levelCount[2],
          level3Count: levelCount[3],
          level4Count: levelCount[4],
          level5Count: levelCount[5],
          level6Count: levelCount[6],
        },
      };
    },
  },
};

export default Model;
